xref: /dragonfly/contrib/file/src/softmagic.c (revision 335b9e93)
1 /*
2  * Copyright (c) Ian F. Darwin 1986-1995.
3  * Software written by Ian F. Darwin and others;
4  * maintained 1995-present by Christos Zoulas and others.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice immediately at the beginning of the file, without modification,
11  *    this list of conditions, and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*
29  * softmagic - interpret variable magic from MAGIC
30  */
31 
32 #include "file.h"
33 
34 #ifndef	lint
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.286 2019/05/17 02:24:59 christos Exp $")
36 #endif	/* lint */
37 
38 #include "magic.h"
39 #include <assert.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include "der.h"
45 
46 private int match(struct magic_set *, struct magic *, uint32_t,
47     const struct buffer *, size_t, int, int, int, uint16_t *,
48     uint16_t *, int *, int *, int *, int *);
49 private int mget(struct magic_set *, struct magic *, const struct buffer *,
50     const unsigned char *, size_t,
51     size_t, unsigned int, int, int, int, uint16_t *,
52     uint16_t *, int *, int *, int *, int *);
53 private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
54     const struct buffer *, size_t, unsigned int);
55 private int magiccheck(struct magic_set *, struct magic *);
56 private int32_t mprint(struct magic_set *, struct magic *);
57 private int moffset(struct magic_set *, struct magic *, const struct buffer *,
58     int32_t *);
59 private void mdebug(uint32_t, const char *, size_t);
60 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
61     const unsigned char *, uint32_t, size_t, struct magic *);
62 private int mconvert(struct magic_set *, struct magic *, int);
63 private int print_sep(struct magic_set *, int);
64 private int handle_annotation(struct magic_set *, struct magic *, int);
65 private int cvt_8(union VALUETYPE *, const struct magic *);
66 private int cvt_16(union VALUETYPE *, const struct magic *);
67 private int cvt_32(union VALUETYPE *, const struct magic *);
68 private int cvt_64(union VALUETYPE *, const struct magic *);
69 
70 #define OFFSET_OOB(n, o, i)	((n) < CAST(uint32_t, (o)) || (i) > ((n) - (o)))
71 #define BE64(p) ( \
72     (CAST(uint64_t, (p)->hq[0])<<56)| \
73     (CAST(uint64_t, (p)->hq[1])<<48)| \
74     (CAST(uint64_t, (p)->hq[2])<<40)| \
75     (CAST(uint64_t, (p)->hq[3])<<32)| \
76     (CAST(uint64_t, (p)->hq[4])<<24)| \
77     (CAST(uint64_t, (p)->hq[5])<<16)| \
78     (CAST(uint64_t, (p)->hq[6])<<8)| \
79     (CAST(uint64_t, (p)->hq[7])))
80 #define LE64(p) ( \
81     (CAST(uint64_t, (p)->hq[7])<<56)| \
82     (CAST(uint64_t, (p)->hq[6])<<48)| \
83     (CAST(uint64_t, (p)->hq[5])<<40)| \
84     (CAST(uint64_t, (p)->hq[4])<<32)| \
85     (CAST(uint64_t, (p)->hq[3])<<24)| \
86     (CAST(uint64_t, (p)->hq[2])<<16)| \
87     (CAST(uint64_t, (p)->hq[1])<<8)| \
88     (CAST(uint64_t, (p)->hq[0])))
89 #define LE32(p) ( \
90     (CAST(uint32_t, (p)->hl[3])<<24)| \
91     (CAST(uint32_t, (p)->hl[2])<<16)| \
92     (CAST(uint32_t, (p)->hl[1])<<8)| \
93     (CAST(uint32_t, (p)->hl[0])))
94 #define BE32(p) ( \
95     (CAST(uint32_t, (p)->hl[0])<<24)| \
96     (CAST(uint32_t, (p)->hl[1])<<16)| \
97     (CAST(uint32_t, (p)->hl[2])<<8)| \
98     (CAST(uint32_t, (p)->hl[3])))
99 #define ME32(p) ( \
100     (CAST(uint32_t, (p)->hl[1])<<24)| \
101     (CAST(uint32_t, (p)->hl[0])<<16)| \
102     (CAST(uint32_t, (p)->hl[3])<<8)| \
103     (CAST(uint32_t, (p)->hl[2])))
104 
105 #define BE16(p) ((CAST(uint16_t, (p)->hs[0])<<8)|(CAST(uint16_t, (p)->hs[1])))
106 #define LE16(p) ((CAST(uint16_t, (p)->hs[1])<<8)|(CAST(uint16_t, (p)->hs[0])))
107 #define SEXT(s,v,p) ((s) ? \
108 	CAST(intmax_t, CAST(int##v##_t, p)) : \
109 	CAST(intmax_t, CAST(uint##v##_t, p)))
110 
111 /*
112  * softmagic - lookup one file in parsed, in-memory copy of database
113  * Passed the name and FILE * of one file to be typed.
114  */
115 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
116 protected int
117 file_softmagic(struct magic_set *ms, const struct buffer *b,
118     uint16_t *indir_count, uint16_t *name_count, int mode, int text)
119 {
120 	struct mlist *ml;
121 	int rv, printed_something = 0, need_separator = 0;
122 	uint16_t nc, ic;
123 
124 	if (name_count == NULL) {
125 		nc = 0;
126 		name_count = &nc;
127 	}
128 	if (indir_count == NULL) {
129 		ic = 0;
130 		indir_count = &ic;
131 	}
132 
133 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
134 		if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode,
135 		    text, 0, indir_count, name_count,
136 		    &printed_something, &need_separator, NULL, NULL)) != 0)
137 			return rv;
138 
139 	return 0;
140 }
141 
142 #define FILE_FMTDEBUG
143 #ifdef FILE_FMTDEBUG
144 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
145 
146 private const char * __attribute__((__format_arg__(3)))
147 file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
148 	const char *file, size_t line)
149 {
150 	const char *ptr;
151 
152 	if (strchr(desc, '%') == NULL)
153 		return desc;
154 
155 	ptr = fmtcheck(desc, def);
156 	if (ptr == def)
157 		file_magerror(ms,
158 		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
159 		    " with `%s'", file, line, desc, def);
160 	return ptr;
161 }
162 #else
163 #define F(a, b, c) fmtcheck((b), (c))
164 #endif
165 
166 /*
167  * Go through the whole list, stopping if you find a match.  Process all
168  * the continuations of that match before returning.
169  *
170  * We support multi-level continuations:
171  *
172  *	At any time when processing a successful top-level match, there is a
173  *	current continuation level; it represents the level of the last
174  *	successfully matched continuation.
175  *
176  *	Continuations above that level are skipped as, if we see one, it
177  *	means that the continuation that controls them - i.e, the
178  *	lower-level continuation preceding them - failed to match.
179  *
180  *	Continuations below that level are processed as, if we see one,
181  *	it means we've finished processing or skipping higher-level
182  *	continuations under the control of a successful or unsuccessful
183  *	lower-level continuation, and are now seeing the next lower-level
184  *	continuation and should process it.  The current continuation
185  *	level reverts to the level of the one we're seeing.
186  *
187  *	Continuations at the current level are processed as, if we see
188  *	one, there's no lower-level continuation that may have failed.
189  *
190  *	If a continuation matches, we bump the current continuation level
191  *	so that higher-level continuations are processed.
192  */
193 private int
194 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
195     const struct buffer *b, size_t offset, int mode, int text,
196     int flip, uint16_t *indir_count, uint16_t *name_count,
197     int *printed_something, int *need_separator, int *returnval,
198     int *found_match)
199 {
200 	uint32_t magindex = 0;
201 	unsigned int cont_level = 0;
202 	int found_matchv = 0; /* if a match is found it is set to 1*/
203 	int returnvalv = 0, e;
204 	int firstline = 1; /* a flag to print X\n  X\n- X */
205 	struct buffer bb;
206 	int print = (ms->flags & MAGIC_NODESC) == 0;
207 
208 	/*
209 	 * returnval can be 0 if a match is found, but there was no
210 	 * annotation to be printed.
211 	 */
212 	if (returnval == NULL)
213 		returnval = &returnvalv;
214 	if (found_match == NULL)
215 		found_match = &found_matchv;
216 
217 	if (file_check_mem(ms, cont_level) == -1)
218 		return -1;
219 
220 	for (magindex = 0; magindex < nmagic; magindex++) {
221 		int flush = 0;
222 		struct magic *m = &magic[magindex];
223 
224 		if (m->type != FILE_NAME)
225 		if ((IS_STRING(m->type) &&
226 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
227 		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
228 		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
229 		    (m->flag & mode) != mode) {
230 flush:
231 			/* Skip sub-tests */
232 			while (magindex < nmagic - 1 &&
233 			    magic[magindex + 1].cont_level != 0)
234 				magindex++;
235 			cont_level = 0;
236 			continue; /* Skip to next top-level test*/
237 		}
238 
239 		if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
240 			goto flush;
241 		ms->line = m->lineno;
242 
243 		/* if main entry matches, print it... */
244 		switch (mget(ms, m, b, CAST(const unsigned char *, bb.fbuf),
245 		    bb.flen, offset, cont_level,
246 		    mode, text, flip, indir_count, name_count,
247 		    printed_something, need_separator, returnval, found_match))
248 		{
249 		case -1:
250 			return -1;
251 		case 0:
252 			flush = m->reln != '!';
253 			break;
254 		default:
255 			if (m->type == FILE_INDIRECT) {
256 				*found_match = 1;
257 				*returnval = 1;
258 			}
259 
260 			switch (magiccheck(ms, m)) {
261 			case -1:
262 				return -1;
263 			case 0:
264 				flush++;
265 				break;
266 			default:
267 				flush = 0;
268 				break;
269 			}
270 			break;
271 		}
272 		if (flush) {
273 			/*
274 			 * main entry didn't match,
275 			 * flush its continuations
276 			 */
277 			goto flush;
278 		}
279 
280 		if (*m->desc)
281 			*found_match = 1;
282 
283 		if ((e = handle_annotation(ms, m, firstline)) != 0)
284 		{
285 			*need_separator = 1;
286 			*printed_something = 1;
287 			*returnval = 1;
288 			return e;
289 		}
290 
291 		/*
292 		 * If we are going to print something, we'll need to print
293 		 * a blank before we print something else.
294 		 */
295 		if (print && *m->desc) {
296 			*need_separator = 1;
297 			*printed_something = 1;
298 			*returnval = 1;
299 			if (print_sep(ms, firstline) == -1)
300 				return -1;
301 			if (mprint(ms, m) == -1)
302 				return -1;
303 		}
304 
305 		switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) {
306 		case -1:
307 		case 0:
308 			goto flush;
309 		default:
310 			break;
311 		}
312 
313 		/* and any continuations that match */
314 		if (file_check_mem(ms, ++cont_level) == -1)
315 			return -1;
316 
317 		while (magindex + 1 < nmagic &&
318 		    magic[magindex + 1].cont_level != 0) {
319 			m = &magic[++magindex];
320 			ms->line = m->lineno; /* for messages */
321 
322 			if (cont_level < m->cont_level)
323 				continue;
324 			if (cont_level > m->cont_level) {
325 				/*
326 				 * We're at the end of the level
327 				 * "cont_level" continuations.
328 				 */
329 				cont_level = m->cont_level;
330 			}
331 			if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
332 				goto flush;
333 			if (m->flag & OFFADD) {
334 				ms->offset +=
335 				    ms->c.li[cont_level - 1].off;
336 			}
337 
338 #ifdef ENABLE_CONDITIONALS
339 			if (m->cond == COND_ELSE ||
340 			    m->cond == COND_ELIF) {
341 				if (ms->c.li[cont_level].last_match == 1)
342 					continue;
343 			}
344 #endif
345 			switch (mget(ms, m, b, CAST(const unsigned char *,
346 			    bb.fbuf), bb.flen, offset,
347 			    cont_level, mode, text, flip, indir_count,
348 			    name_count, printed_something, need_separator,
349 			    returnval, found_match)) {
350 			case -1:
351 				return -1;
352 			case 0:
353 				if (m->reln != '!')
354 					continue;
355 				flush = 1;
356 				break;
357 			default:
358 				if (m->type == FILE_INDIRECT) {
359 					*found_match = 1;
360 					*returnval = 1;
361 				}
362 				flush = 0;
363 				break;
364 			}
365 
366 			switch (flush ? 1 : magiccheck(ms, m)) {
367 			case -1:
368 				return -1;
369 			case 0:
370 #ifdef ENABLE_CONDITIONALS
371 				ms->c.li[cont_level].last_match = 0;
372 #endif
373 				break;
374 			default:
375 #ifdef ENABLE_CONDITIONALS
376 				ms->c.li[cont_level].last_match = 1;
377 #endif
378 				if (m->type == FILE_CLEAR)
379 					ms->c.li[cont_level].got_match = 0;
380 				else if (ms->c.li[cont_level].got_match) {
381 					if (m->type == FILE_DEFAULT)
382 						break;
383 				} else
384 					ms->c.li[cont_level].got_match = 1;
385 
386 				if (*m->desc)
387 					*found_match = 1;
388 
389 				if ((e = handle_annotation(ms, m, firstline))
390 				    != 0) {
391 					*need_separator = 1;
392 					*printed_something = 1;
393 					*returnval = 1;
394 					return e;
395 				}
396 				if (print && *m->desc) {
397 					/*
398 					 * This continuation matched.  Print
399 					 * its message, with a blank before it
400 					 * if the previous item printed and
401 					 * this item isn't empty.
402 					 */
403 					/*
404 					 * If we are going to print something,
405 					 * make sure that we have a separator
406 					 * first.
407 					 */
408 					if (!*printed_something) {
409 						*printed_something = 1;
410 						if (print_sep(ms, firstline)
411 						    == -1)
412 							return -1;
413 					}
414 					/* space if previous printed */
415 					if (*need_separator
416 					    && (m->flag & NOSPACE) == 0) {
417 						if (file_printf(ms, " ") == -1)
418 							return -1;
419 					}
420 					*returnval = 1;
421 					*need_separator = 0;
422 					if (mprint(ms, m) == -1)
423 						return -1;
424 					*need_separator = 1;
425 				}
426 
427 				switch (moffset(ms, m, &bb,
428 				    &ms->c.li[cont_level].off)) {
429 				case -1:
430 				case 0:
431 					flush = 1;
432 					cont_level--;
433 					break;
434 				default:
435 					break;
436 				}
437 
438 				/*
439 				 * If we see any continuations
440 				 * at a higher level,
441 				 * process them.
442 				 */
443 				if (file_check_mem(ms, ++cont_level) == -1)
444 					return -1;
445 				break;
446 			}
447 		}
448 		if (*printed_something) {
449 			firstline = 0;
450 		}
451 		if (*found_match) {
452 		    if ((ms->flags & MAGIC_CONTINUE) == 0)
453 			return *returnval; /* don't keep searching */
454 		    // So that we print a separator
455 		    *printed_something = 0;
456 		    firstline = 0;
457 		}
458 		cont_level = 0;
459 	}
460 	return *returnval;  /* This is hit if -k is set or there is no match */
461 }
462 
463 private int
464 check_fmt(struct magic_set *ms, const char *fmt)
465 {
466 	file_regex_t rx;
467 	int rc, rv = -1;
468 
469 	if (strchr(fmt, '%') == NULL)
470 		return 0;
471 
472 	rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
473 	if (rc) {
474 		file_regerror(&rx, rc, ms);
475 	} else {
476 		rc = file_regexec(&rx, fmt, 0, 0, 0);
477 		rv = !rc;
478 	}
479 	file_regfree(&rx);
480 	return rv;
481 }
482 
483 #if !defined(HAVE_STRNDUP) || defined(__aiws__)
484 # ifdef __aiws__
485 #  define strndup aix_strndup	/* aix is broken */
486 # endif
487 char *strndup(const char *, size_t);
488 
489 char *
490 strndup(const char *str, size_t n)
491 {
492 	size_t len;
493 	char *copy;
494 
495 	for (len = 0; len < n && str[len]; len++)
496 		continue;
497 	if ((copy = malloc(len + 1)) == NULL)
498 		return NULL;
499 	(void)memcpy(copy, str, len);
500 	copy[len] = '\0';
501 	return copy;
502 }
503 #endif /* HAVE_STRNDUP */
504 
505 static int
506 varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
507 {
508 	const char *ptr, *sptr, *e, *t, *ee, *et;
509 	size_t l;
510 
511 	for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
512 		l = CAST(size_t, ptr - sptr);
513 		if (l >= len)
514 			return -1;
515 		memcpy(buf, sptr, l);
516 		buf += l;
517 		len -= l;
518 		ptr += 2;
519 		if (!*ptr || ptr[1] != '?')
520 			return -1;
521 		for (et = t = ptr + 2; *et && *et != ':'; et++)
522 			continue;
523 		if (*et != ':')
524 			return -1;
525 		for (ee = e = et + 1; *ee && *ee != '}'; ee++)
526 			continue;
527 		if (*ee != '}')
528 			return -1;
529 		switch (*ptr) {
530 		case 'x':
531 			if (ms->mode & 0111) {
532 				ptr = t;
533 				l = et - t;
534 			} else {
535 				ptr = e;
536 				l = ee - e;
537 			}
538 			break;
539 		default:
540 			return -1;
541 		}
542 		if (l >= len)
543 			return -1;
544 		memcpy(buf, ptr, l);
545 		buf += l;
546 		len -= l;
547 		sptr = ee + 1;
548 	}
549 
550 	l = strlen(sptr);
551 	if (l >= len)
552 		return -1;
553 
554 	memcpy(buf, sptr, l);
555 	buf[l] = '\0';
556 	return 0;
557 }
558 
559 
560 private int32_t
561 mprint(struct magic_set *ms, struct magic *m)
562 {
563 	uint64_t v;
564 	float vf;
565 	double vd;
566 	int64_t t = 0;
567  	char buf[128], tbuf[26], sbuf[512], ebuf[512];
568 	const char *desc;
569 	union VALUETYPE *p = &ms->ms_value;
570 
571 	if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1)
572 		desc = m->desc;
573 	else
574 		desc = ebuf;
575 
576   	switch (m->type) {
577   	case FILE_BYTE:
578 		v = file_signextend(ms, m, CAST(uint64_t, p->b));
579 		switch (check_fmt(ms, desc)) {
580 		case -1:
581 			return -1;
582 		case 1:
583 			(void)snprintf(buf, sizeof(buf), "%d",
584 			    CAST(unsigned char, v));
585 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
586 				return -1;
587 			break;
588 		default:
589 			if (file_printf(ms, F(ms, desc, "%d"),
590 			    CAST(unsigned char, v)) == -1)
591 				return -1;
592 			break;
593 		}
594 		t = ms->offset + sizeof(char);
595 		break;
596 
597   	case FILE_SHORT:
598   	case FILE_BESHORT:
599   	case FILE_LESHORT:
600 		v = file_signextend(ms, m, CAST(uint64_t, p->h));
601 		switch (check_fmt(ms, desc)) {
602 		case -1:
603 			return -1;
604 		case 1:
605 			(void)snprintf(buf, sizeof(buf), "%u",
606 			    CAST(unsigned short, v));
607 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
608 				return -1;
609 			break;
610 		default:
611 			if (file_printf(ms, F(ms, desc, "%u"),
612 			    CAST(unsigned short, v)) == -1)
613 				return -1;
614 			break;
615 		}
616 		t = ms->offset + sizeof(short);
617 		break;
618 
619   	case FILE_LONG:
620   	case FILE_BELONG:
621   	case FILE_LELONG:
622   	case FILE_MELONG:
623 		v = file_signextend(ms, m, CAST(uint64_t, p->l));
624 		switch (check_fmt(ms, desc)) {
625 		case -1:
626 			return -1;
627 		case 1:
628 			(void)snprintf(buf, sizeof(buf), "%u",
629 			    CAST(uint32_t, v));
630 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
631 				return -1;
632 			break;
633 		default:
634 			if (file_printf(ms, F(ms, desc, "%u"),
635 			    CAST(uint32_t, v)) == -1)
636 				return -1;
637 			break;
638 		}
639 		t = ms->offset + sizeof(int32_t);
640   		break;
641 
642   	case FILE_QUAD:
643   	case FILE_BEQUAD:
644   	case FILE_LEQUAD:
645 		v = file_signextend(ms, m, p->q);
646 		switch (check_fmt(ms, desc)) {
647 		case -1:
648 			return -1;
649 		case 1:
650 			(void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
651 			    CAST(unsigned long long, v));
652 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
653 				return -1;
654 			break;
655 		default:
656 			if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"),
657 			    CAST(unsigned long long, v)) == -1)
658 				return -1;
659 			break;
660 		}
661 		t = ms->offset + sizeof(int64_t);
662   		break;
663 
664   	case FILE_STRING:
665   	case FILE_PSTRING:
666   	case FILE_BESTRING16:
667   	case FILE_LESTRING16:
668 		if (m->reln == '=' || m->reln == '!') {
669 			if (file_printf(ms, F(ms, desc, "%s"),
670 			    file_printable(sbuf, sizeof(sbuf), m->value.s,
671 			    sizeof(m->value.s))) == -1)
672 				return -1;
673 			t = ms->offset + m->vallen;
674 		}
675 		else {
676 			char *str = p->s;
677 
678 			/* compute t before we mangle the string? */
679 			t = ms->offset + strlen(str);
680 
681 			if (*m->value.s == '\0')
682 				str[strcspn(str, "\r\n")] = '\0';
683 
684 			if (m->str_flags & STRING_TRIM) {
685 				char *last;
686 				while (isspace(CAST(unsigned char, *str)))
687 					str++;
688 				last = str;
689 				while (*last)
690 					last++;
691 				--last;
692 				while (isspace(CAST(unsigned char, *last)))
693 					last--;
694 				*++last = '\0';
695 			}
696 
697 			if (file_printf(ms, F(ms, desc, "%s"),
698 			    file_printable(sbuf, sizeof(sbuf), str,
699 				sizeof(p->s) - (str - p->s))) == -1)
700 				return -1;
701 
702 			if (m->type == FILE_PSTRING)
703 				t += file_pstring_length_size(m);
704 		}
705 		break;
706 
707 	case FILE_DATE:
708 	case FILE_BEDATE:
709 	case FILE_LEDATE:
710 	case FILE_MEDATE:
711 		if (file_printf(ms, F(ms, desc, "%s"),
712 		    file_fmttime(p->l, 0, tbuf)) == -1)
713 			return -1;
714 		t = ms->offset + sizeof(uint32_t);
715 		break;
716 
717 	case FILE_LDATE:
718 	case FILE_BELDATE:
719 	case FILE_LELDATE:
720 	case FILE_MELDATE:
721 		if (file_printf(ms, F(ms, desc, "%s"),
722 		    file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
723 			return -1;
724 		t = ms->offset + sizeof(uint32_t);
725 		break;
726 
727 	case FILE_QDATE:
728 	case FILE_BEQDATE:
729 	case FILE_LEQDATE:
730 		if (file_printf(ms, F(ms, desc, "%s"),
731 		    file_fmttime(p->q, 0, tbuf)) == -1)
732 			return -1;
733 		t = ms->offset + sizeof(uint64_t);
734 		break;
735 
736 	case FILE_QLDATE:
737 	case FILE_BEQLDATE:
738 	case FILE_LEQLDATE:
739 		if (file_printf(ms, F(ms, desc, "%s"),
740 		    file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
741 			return -1;
742 		t = ms->offset + sizeof(uint64_t);
743 		break;
744 
745 	case FILE_QWDATE:
746 	case FILE_BEQWDATE:
747 	case FILE_LEQWDATE:
748 		if (file_printf(ms, F(ms, desc, "%s"),
749 		    file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
750 			return -1;
751 		t = ms->offset + sizeof(uint64_t);
752 		break;
753 
754 	case FILE_FLOAT:
755 	case FILE_BEFLOAT:
756 	case FILE_LEFLOAT:
757 		vf = p->f;
758 		switch (check_fmt(ms, desc)) {
759 		case -1:
760 			return -1;
761 		case 1:
762 			(void)snprintf(buf, sizeof(buf), "%g", vf);
763 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
764 				return -1;
765 			break;
766 		default:
767 			if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
768 				return -1;
769 			break;
770 		}
771 		t = ms->offset + sizeof(float);
772   		break;
773 
774 	case FILE_DOUBLE:
775 	case FILE_BEDOUBLE:
776 	case FILE_LEDOUBLE:
777 		vd = p->d;
778 		switch (check_fmt(ms, desc)) {
779 		case -1:
780 			return -1;
781 		case 1:
782 			(void)snprintf(buf, sizeof(buf), "%g", vd);
783 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
784 				return -1;
785 			break;
786 		default:
787 			if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
788 				return -1;
789 			break;
790 		}
791 		t = ms->offset + sizeof(double);
792   		break;
793 
794 	case FILE_SEARCH:
795 	case FILE_REGEX: {
796 		char *cp;
797 		int rval;
798 
799 		cp = strndup(RCAST(const char *, ms->search.s),
800 		    ms->search.rm_len);
801 		if (cp == NULL) {
802 			file_oomem(ms, ms->search.rm_len);
803 			return -1;
804 		}
805 		rval = file_printf(ms, F(ms, desc, "%s"),
806 		    file_printable(sbuf, sizeof(sbuf), cp, ms->search.rm_len));
807 		free(cp);
808 
809 		if (rval == -1)
810 			return -1;
811 
812 		if ((m->str_flags & REGEX_OFFSET_START))
813 			t = ms->search.offset;
814 		else
815 			t = ms->search.offset + ms->search.rm_len;
816 		break;
817 	}
818 
819 	case FILE_DEFAULT:
820 	case FILE_CLEAR:
821 	  	if (file_printf(ms, "%s", m->desc) == -1)
822 			return -1;
823 		t = ms->offset;
824 		break;
825 
826 	case FILE_INDIRECT:
827 	case FILE_USE:
828 	case FILE_NAME:
829 		t = ms->offset;
830 		break;
831 	case FILE_DER:
832 		if (file_printf(ms, F(ms, desc, "%s"),
833 		    file_printable(sbuf, sizeof(sbuf), ms->ms_value.s,
834 			sizeof(ms->ms_value.s))) == -1)
835 			return -1;
836 		t = ms->offset;
837 		break;
838 	default:
839 		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
840 		return -1;
841 	}
842 	return CAST(int32_t, t);
843 }
844 
845 private int
846 moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
847     int32_t *op)
848 {
849 	size_t nbytes = b->flen;
850 	int32_t o;
851 
852   	switch (m->type) {
853   	case FILE_BYTE:
854 		o = CAST(int32_t, (ms->offset + sizeof(char)));
855 		break;
856 
857   	case FILE_SHORT:
858   	case FILE_BESHORT:
859   	case FILE_LESHORT:
860 		o = CAST(int32_t, (ms->offset + sizeof(short)));
861 		break;
862 
863   	case FILE_LONG:
864   	case FILE_BELONG:
865   	case FILE_LELONG:
866   	case FILE_MELONG:
867 		o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
868 		break;
869 
870   	case FILE_QUAD:
871   	case FILE_BEQUAD:
872   	case FILE_LEQUAD:
873 		o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
874 		break;
875 
876   	case FILE_STRING:
877   	case FILE_PSTRING:
878   	case FILE_BESTRING16:
879   	case FILE_LESTRING16:
880 		if (m->reln == '=' || m->reln == '!') {
881 			o = ms->offset + m->vallen;
882 		} else {
883 			union VALUETYPE *p = &ms->ms_value;
884 
885 			if (*m->value.s == '\0')
886 				p->s[strcspn(p->s, "\r\n")] = '\0';
887 			o = CAST(uint32_t, (ms->offset + strlen(p->s)));
888 			if (m->type == FILE_PSTRING)
889 				o += CAST(uint32_t,
890 				    file_pstring_length_size(m));
891 		}
892 		break;
893 
894 	case FILE_DATE:
895 	case FILE_BEDATE:
896 	case FILE_LEDATE:
897 	case FILE_MEDATE:
898 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
899 		break;
900 
901 	case FILE_LDATE:
902 	case FILE_BELDATE:
903 	case FILE_LELDATE:
904 	case FILE_MELDATE:
905 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
906 		break;
907 
908 	case FILE_QDATE:
909 	case FILE_BEQDATE:
910 	case FILE_LEQDATE:
911 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
912 		break;
913 
914 	case FILE_QLDATE:
915 	case FILE_BEQLDATE:
916 	case FILE_LEQLDATE:
917 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
918 		break;
919 
920   	case FILE_FLOAT:
921   	case FILE_BEFLOAT:
922   	case FILE_LEFLOAT:
923 		o = CAST(int32_t, (ms->offset + sizeof(float)));
924 		break;
925 
926   	case FILE_DOUBLE:
927   	case FILE_BEDOUBLE:
928   	case FILE_LEDOUBLE:
929 		o = CAST(int32_t, (ms->offset + sizeof(double)));
930 		break;
931 
932 	case FILE_REGEX:
933 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
934 			o = CAST(int32_t, ms->search.offset);
935 		else
936 			o = CAST(int32_t,
937 			    (ms->search.offset + ms->search.rm_len));
938 		break;
939 
940 	case FILE_SEARCH:
941 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
942 			o = CAST(int32_t, ms->search.offset);
943 		else
944 			o = CAST(int32_t, (ms->search.offset + m->vallen));
945 		break;
946 
947 	case FILE_CLEAR:
948 	case FILE_DEFAULT:
949 	case FILE_INDIRECT:
950 		o = ms->offset;
951 		break;
952 
953 	case FILE_DER:
954 		{
955 			o = der_offs(ms, m, nbytes);
956 			if (o == -1 || CAST(size_t, o) > nbytes) {
957 				if ((ms->flags & MAGIC_DEBUG) != 0) {
958 					(void)fprintf(stderr,
959 					    "Bad DER offset %d nbytes=%"
960 					    SIZE_T_FORMAT "u", o, nbytes);
961 				}
962 				*op = 0;
963 				return 0;
964 			}
965 			break;
966 		}
967 
968 	default:
969 		o = 0;
970 		break;
971 	}
972 
973 	if (CAST(size_t, o) > nbytes) {
974 #if 0
975 		file_error(ms, 0, "Offset out of range %" SIZE_T_FORMAT
976 		    "u > %" SIZE_T_FORMAT "u", (size_t)o, nbytes);
977 #endif
978 		return -1;
979 	}
980 	*op = o;
981 	return 1;
982 }
983 
984 private uint32_t
985 cvt_id3(struct magic_set *ms, uint32_t v)
986 {
987 	v = ((((v >>  0) & 0x7f) <<  0) |
988 	     (((v >>  8) & 0x7f) <<  7) |
989 	     (((v >> 16) & 0x7f) << 14) |
990 	     (((v >> 24) & 0x7f) << 21));
991 	if ((ms->flags & MAGIC_DEBUG) != 0)
992 		fprintf(stderr, "id3 offs=%u\n", v);
993 	return v;
994 }
995 
996 private int
997 cvt_flip(int type, int flip)
998 {
999 	if (flip == 0)
1000 		return type;
1001 	switch (type) {
1002 	case FILE_BESHORT:
1003 		return FILE_LESHORT;
1004 	case FILE_BELONG:
1005 		return FILE_LELONG;
1006 	case FILE_BEDATE:
1007 		return FILE_LEDATE;
1008 	case FILE_BELDATE:
1009 		return FILE_LELDATE;
1010 	case FILE_BEQUAD:
1011 		return FILE_LEQUAD;
1012 	case FILE_BEQDATE:
1013 		return FILE_LEQDATE;
1014 	case FILE_BEQLDATE:
1015 		return FILE_LEQLDATE;
1016 	case FILE_BEQWDATE:
1017 		return FILE_LEQWDATE;
1018 	case FILE_LESHORT:
1019 		return FILE_BESHORT;
1020 	case FILE_LELONG:
1021 		return FILE_BELONG;
1022 	case FILE_LEDATE:
1023 		return FILE_BEDATE;
1024 	case FILE_LELDATE:
1025 		return FILE_BELDATE;
1026 	case FILE_LEQUAD:
1027 		return FILE_BEQUAD;
1028 	case FILE_LEQDATE:
1029 		return FILE_BEQDATE;
1030 	case FILE_LEQLDATE:
1031 		return FILE_BEQLDATE;
1032 	case FILE_LEQWDATE:
1033 		return FILE_BEQWDATE;
1034 	case FILE_BEFLOAT:
1035 		return FILE_LEFLOAT;
1036 	case FILE_LEFLOAT:
1037 		return FILE_BEFLOAT;
1038 	case FILE_BEDOUBLE:
1039 		return FILE_LEDOUBLE;
1040 	case FILE_LEDOUBLE:
1041 		return FILE_BEDOUBLE;
1042 	default:
1043 		return type;
1044 	}
1045 }
1046 #define DO_CVT(fld, type) \
1047 	if (m->num_mask) \
1048 		switch (m->mask_op & FILE_OPS_MASK) { \
1049 		case FILE_OPAND: \
1050 			p->fld &= CAST(type, m->num_mask); \
1051 			break; \
1052 		case FILE_OPOR: \
1053 			p->fld |= CAST(type, m->num_mask); \
1054 			break; \
1055 		case FILE_OPXOR: \
1056 			p->fld ^= CAST(type, m->num_mask); \
1057 			break; \
1058 		case FILE_OPADD: \
1059 			p->fld += CAST(type, m->num_mask); \
1060 			break; \
1061 		case FILE_OPMINUS: \
1062 			p->fld -= CAST(type, m->num_mask); \
1063 			break; \
1064 		case FILE_OPMULTIPLY: \
1065 			p->fld *= CAST(type, m->num_mask); \
1066 			break; \
1067 		case FILE_OPDIVIDE: \
1068 			if (CAST(type, m->num_mask) == 0) \
1069 				return -1; \
1070 			p->fld /= CAST(type, m->num_mask); \
1071 			break; \
1072 		case FILE_OPMODULO: \
1073 			if (CAST(type, m->num_mask) == 0) \
1074 				return -1; \
1075 			p->fld %= CAST(type, m->num_mask); \
1076 			break; \
1077 		} \
1078 	if (m->mask_op & FILE_OPINVERSE) \
1079 		p->fld = ~p->fld \
1080 
1081 private int
1082 cvt_8(union VALUETYPE *p, const struct magic *m)
1083 {
1084 	DO_CVT(b, uint8_t);
1085 	return 0;
1086 }
1087 
1088 private int
1089 cvt_16(union VALUETYPE *p, const struct magic *m)
1090 {
1091 	DO_CVT(h, uint16_t);
1092 	return 0;
1093 }
1094 
1095 private int
1096 cvt_32(union VALUETYPE *p, const struct magic *m)
1097 {
1098 	DO_CVT(l, uint32_t);
1099 	return 0;
1100 }
1101 
1102 private int
1103 cvt_64(union VALUETYPE *p, const struct magic *m)
1104 {
1105 	DO_CVT(q, uint64_t);
1106 	return 0;
1107 }
1108 
1109 #define DO_CVT2(fld, type) \
1110 	if (m->num_mask) \
1111 		switch (m->mask_op & FILE_OPS_MASK) { \
1112 		case FILE_OPADD: \
1113 			p->fld += CAST(type, m->num_mask); \
1114 			break; \
1115 		case FILE_OPMINUS: \
1116 			p->fld -= CAST(type, m->num_mask); \
1117 			break; \
1118 		case FILE_OPMULTIPLY: \
1119 			p->fld *= CAST(type, m->num_mask); \
1120 			break; \
1121 		case FILE_OPDIVIDE: \
1122 			if (CAST(type, m->num_mask) == 0) \
1123 				return -1; \
1124 			p->fld /= CAST(type, m->num_mask); \
1125 			break; \
1126 		} \
1127 
1128 private int
1129 cvt_float(union VALUETYPE *p, const struct magic *m)
1130 {
1131 	DO_CVT2(f, float);
1132 	return 0;
1133 }
1134 
1135 private int
1136 cvt_double(union VALUETYPE *p, const struct magic *m)
1137 {
1138 	DO_CVT2(d, double);
1139 	return 0;
1140 }
1141 
1142 /*
1143  * Convert the byte order of the data we are looking at
1144  * While we're here, let's apply the mask operation
1145  * (unless you have a better idea)
1146  */
1147 private int
1148 mconvert(struct magic_set *ms, struct magic *m, int flip)
1149 {
1150 	union VALUETYPE *p = &ms->ms_value;
1151 
1152 	switch (cvt_flip(m->type, flip)) {
1153 	case FILE_BYTE:
1154 		if (cvt_8(p, m) == -1)
1155 			goto out;
1156 		return 1;
1157 	case FILE_SHORT:
1158 		if (cvt_16(p, m) == -1)
1159 			goto out;
1160 		return 1;
1161 	case FILE_LONG:
1162 	case FILE_DATE:
1163 	case FILE_LDATE:
1164 		if (cvt_32(p, m) == -1)
1165 			goto out;
1166 		return 1;
1167 	case FILE_QUAD:
1168 	case FILE_QDATE:
1169 	case FILE_QLDATE:
1170 	case FILE_QWDATE:
1171 		if (cvt_64(p, m) == -1)
1172 			goto out;
1173 		return 1;
1174 	case FILE_STRING:
1175 	case FILE_BESTRING16:
1176 	case FILE_LESTRING16: {
1177 		/* Null terminate and eat *trailing* return */
1178 		p->s[sizeof(p->s) - 1] = '\0';
1179 		return 1;
1180 	}
1181 	case FILE_PSTRING: {
1182 		size_t sz = file_pstring_length_size(m);
1183 		char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1184 		size_t len = file_pstring_get_length(m, ptr1);
1185 		sz = sizeof(p->s) - sz; /* maximum length of string */
1186 		if (len >= sz) {
1187 			/*
1188 			 * The size of the pascal string length (sz)
1189 			 * is 1, 2, or 4. We need at least 1 byte for NUL
1190 			 * termination, but we've already truncated the
1191 			 * string by p->s, so we need to deduct sz.
1192 			 * Because we can use one of the bytes of the length
1193 			 * after we shifted as NUL termination.
1194 			 */
1195 			len = sz;
1196 		}
1197 		while (len--)
1198 			*ptr1++ = *ptr2++;
1199 		*ptr1 = '\0';
1200 		return 1;
1201 	}
1202 	case FILE_BESHORT:
1203 		p->h = CAST(short, BE16(p));
1204 		if (cvt_16(p, m) == -1)
1205 			goto out;
1206 		return 1;
1207 	case FILE_BELONG:
1208 	case FILE_BEDATE:
1209 	case FILE_BELDATE:
1210 		p->l = CAST(int32_t, BE32(p));
1211 		if (cvt_32(p, m) == -1)
1212 			goto out;
1213 		return 1;
1214 	case FILE_BEQUAD:
1215 	case FILE_BEQDATE:
1216 	case FILE_BEQLDATE:
1217 	case FILE_BEQWDATE:
1218 		p->q = CAST(uint64_t, BE64(p));
1219 		if (cvt_64(p, m) == -1)
1220 			goto out;
1221 		return 1;
1222 	case FILE_LESHORT:
1223 		p->h = CAST(short, LE16(p));
1224 		if (cvt_16(p, m) == -1)
1225 			goto out;
1226 		return 1;
1227 	case FILE_LELONG:
1228 	case FILE_LEDATE:
1229 	case FILE_LELDATE:
1230 		p->l = CAST(int32_t, LE32(p));
1231 		if (cvt_32(p, m) == -1)
1232 			goto out;
1233 		return 1;
1234 	case FILE_LEQUAD:
1235 	case FILE_LEQDATE:
1236 	case FILE_LEQLDATE:
1237 	case FILE_LEQWDATE:
1238 		p->q = CAST(uint64_t, LE64(p));
1239 		if (cvt_64(p, m) == -1)
1240 			goto out;
1241 		return 1;
1242 	case FILE_MELONG:
1243 	case FILE_MEDATE:
1244 	case FILE_MELDATE:
1245 		p->l = CAST(int32_t, ME32(p));
1246 		if (cvt_32(p, m) == -1)
1247 			goto out;
1248 		return 1;
1249 	case FILE_FLOAT:
1250 		if (cvt_float(p, m) == -1)
1251 			goto out;
1252 		return 1;
1253 	case FILE_BEFLOAT:
1254 		p->l = BE32(p);
1255 		if (cvt_float(p, m) == -1)
1256 			goto out;
1257 		return 1;
1258 	case FILE_LEFLOAT:
1259 		p->l = LE32(p);
1260 		if (cvt_float(p, m) == -1)
1261 			goto out;
1262 		return 1;
1263 	case FILE_DOUBLE:
1264 		if (cvt_double(p, m) == -1)
1265 			goto out;
1266 		return 1;
1267 	case FILE_BEDOUBLE:
1268 		p->q = BE64(p);
1269 		if (cvt_double(p, m) == -1)
1270 			goto out;
1271 		return 1;
1272 	case FILE_LEDOUBLE:
1273 		p->q = LE64(p);
1274 		if (cvt_double(p, m) == -1)
1275 			goto out;
1276 		return 1;
1277 	case FILE_REGEX:
1278 	case FILE_SEARCH:
1279 	case FILE_DEFAULT:
1280 	case FILE_CLEAR:
1281 	case FILE_NAME:
1282 	case FILE_USE:
1283 	case FILE_DER:
1284 		return 1;
1285 	default:
1286 		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1287 		return 0;
1288 	}
1289 out:
1290 	file_magerror(ms, "zerodivide in mconvert()");
1291 	return 0;
1292 }
1293 
1294 
1295 private void
1296 mdebug(uint32_t offset, const char *str, size_t len)
1297 {
1298 	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1299 	file_showstr(stderr, str, len);
1300 	(void) fputc('\n', stderr);
1301 	(void) fputc('\n', stderr);
1302 }
1303 
1304 private int
1305 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1306     const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1307 {
1308 	/*
1309 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1310 	 * anything, but setup pointers into the source
1311 	 */
1312 	if (indir == 0) {
1313 		switch (type) {
1314 		case FILE_DER:
1315 		case FILE_SEARCH:
1316 			if (offset > nbytes)
1317 				offset = CAST(uint32_t, nbytes);
1318 			ms->search.s = RCAST(const char *, s) + offset;
1319 			ms->search.s_len = nbytes - offset;
1320 			ms->search.offset = offset;
1321 			return 0;
1322 
1323 		case FILE_REGEX: {
1324 			const char *b;
1325 			const char *c;
1326 			const char *last;	/* end of search region */
1327 			const char *buf;	/* start of search region */
1328 			const char *end;
1329 			size_t lines, linecnt, bytecnt;
1330 
1331 			if (s == NULL || nbytes < offset) {
1332 				ms->search.s_len = 0;
1333 				ms->search.s = NULL;
1334 				return 0;
1335 			}
1336 
1337 			if (m->str_flags & REGEX_LINE_COUNT) {
1338 				linecnt = m->str_range;
1339 				bytecnt = linecnt * 80;
1340 			} else {
1341 				linecnt = 0;
1342 				bytecnt = m->str_range;
1343 			}
1344 
1345 			if (bytecnt == 0 || bytecnt > nbytes - offset)
1346 				bytecnt = nbytes - offset;
1347 			if (bytecnt > ms->regex_max)
1348 				bytecnt = ms->regex_max;
1349 
1350 			buf = RCAST(const char *, s) + offset;
1351 			end = last = RCAST(const char *, s) + bytecnt + offset;
1352 			/* mget() guarantees buf <= last */
1353 			for (lines = linecnt, b = buf; lines && b < end &&
1354 			     ((b = CAST(const char *,
1355 				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1356 			     || (b = CAST(const char *,
1357 				 memchr(c, '\r', CAST(size_t, (end - c))))));
1358 			     lines--, b++) {
1359 				if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1360 					b++;
1361 				if (b < end - 1 && b[0] == '\n')
1362 					b++;
1363 				last = b;
1364 			}
1365 			if (lines)
1366 				last = end;
1367 
1368 			ms->search.s = buf;
1369 			ms->search.s_len = last - buf;
1370 			ms->search.offset = offset;
1371 			ms->search.rm_len = 0;
1372 			return 0;
1373 		}
1374 		case FILE_BESTRING16:
1375 		case FILE_LESTRING16: {
1376 			const unsigned char *src = s + offset;
1377 			const unsigned char *esrc = s + nbytes;
1378 			char *dst = p->s;
1379 			char *edst = &p->s[sizeof(p->s) - 1];
1380 
1381 			if (type == FILE_BESTRING16)
1382 				src++;
1383 
1384 			/* check that offset is within range */
1385 			if (offset >= nbytes)
1386 				break;
1387 			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1388 				if (dst < edst)
1389 					*dst = *src;
1390 				else
1391 					break;
1392 				if (*dst == '\0') {
1393 					if (type == FILE_BESTRING16 ?
1394 					    *(src - 1) != '\0' :
1395 					    ((src + 1 < esrc) &&
1396 					    *(src + 1) != '\0'))
1397 						*dst = ' ';
1398 				}
1399 			}
1400 			*edst = '\0';
1401 			return 0;
1402 		}
1403 		case FILE_STRING:	/* XXX - these two should not need */
1404 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1405 		default:
1406 			break;
1407 		}
1408 	}
1409 
1410 	if (offset >= nbytes) {
1411 		(void)memset(p, '\0', sizeof(*p));
1412 		return 0;
1413 	}
1414 	if (nbytes - offset < sizeof(*p))
1415 		nbytes = nbytes - offset;
1416 	else
1417 		nbytes = sizeof(*p);
1418 
1419 	(void)memcpy(p, s + offset, nbytes);
1420 
1421 	/*
1422 	 * the usefulness of padding with zeroes eludes me, it
1423 	 * might even cause problems
1424 	 */
1425 	if (nbytes < sizeof(*p))
1426 		(void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0',
1427 		    sizeof(*p) - nbytes);
1428 	return 0;
1429 }
1430 
1431 private uint32_t
1432 do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1433 {
1434 	intmax_t offset = 0;
1435 	if (off) {
1436 		switch (m->in_op & FILE_OPS_MASK) {
1437 		case FILE_OPAND:
1438 			offset = lhs & off;
1439 			break;
1440 		case FILE_OPOR:
1441 			offset = lhs | off;
1442 			break;
1443 		case FILE_OPXOR:
1444 			offset = lhs ^ off;
1445 			break;
1446 		case FILE_OPADD:
1447 			offset = lhs + off;
1448 			break;
1449 		case FILE_OPMINUS:
1450 			offset = lhs - off;
1451 			break;
1452 		case FILE_OPMULTIPLY:
1453 			offset = lhs * off;
1454 			break;
1455 		case FILE_OPDIVIDE:
1456 			offset = lhs / off;
1457 			break;
1458 		case FILE_OPMODULO:
1459 			offset = lhs % off;
1460 			break;
1461 		}
1462 	} else
1463 		offset = lhs;
1464 	if (m->in_op & FILE_OPINVERSE)
1465 		offset = ~offset;
1466 
1467 	return CAST(uint32_t, offset);
1468 }
1469 
1470 private int
1471 msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
1472     const struct buffer *b, size_t o, unsigned int cont_level)
1473 {
1474 	if (m->offset < 0) {
1475 		if (cont_level > 0) {
1476 			if (m->flag & (OFFADD|INDIROFFADD))
1477 				goto normal;
1478 #if 0
1479 			file_error(ms, 0, "negative offset %d at continuation"
1480 			    "level %u", m->offset, cont_level);
1481 			return -1;
1482 #endif
1483 		}
1484 		if (buffer_fill(b) == -1)
1485 			return -1;
1486 		if (o != 0) {
1487 			// Not yet!
1488 			file_magerror(ms, "non zero offset %" SIZE_T_FORMAT
1489 			    "u at level %u", o, cont_level);
1490 			return -1;
1491 		}
1492 		if (CAST(size_t, -m->offset) > b->elen)
1493 			return -1;
1494 		buffer_init(bb, -1, NULL, b->ebuf, b->elen);
1495 		ms->eoffset = ms->offset = CAST(int32_t, b->elen + m->offset);
1496 	} else {
1497 		if (cont_level == 0) {
1498 normal:
1499 			// XXX: Pass real fd, then who frees bb?
1500 			buffer_init(bb, -1, NULL, b->fbuf, b->flen);
1501 			ms->offset = m->offset;
1502 			ms->eoffset = 0;
1503 		} else {
1504 			ms->offset = ms->eoffset + m->offset;
1505 		}
1506 	}
1507 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1508 		fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u], %d [b=%p,%"
1509 		    SIZE_T_FORMAT "u], [o=%#x, c=%d]\n",
1510 		    bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen,
1511 		    m->offset, cont_level);
1512 	}
1513 	return 0;
1514 }
1515 
1516 private int
1517 mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
1518     const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
1519     int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1520     int *printed_something, int *need_separator, int *returnval,
1521     int *found_match)
1522 {
1523 	uint32_t offset = ms->offset;
1524 	struct buffer bb;
1525 	intmax_t lhs;
1526 	file_pushbuf_t *pb;
1527 	int rv, oneed_separator, in_type;
1528 	char *rbuf;
1529 	union VALUETYPE *p = &ms->ms_value;
1530 	struct mlist ml;
1531 
1532 	if (*indir_count >= ms->indir_max) {
1533 		file_error(ms, 0, "indirect count (%hu) exceeded",
1534 		    *indir_count);
1535 		return -1;
1536 	}
1537 
1538 	if (*name_count >= ms->name_max) {
1539 		file_error(ms, 0, "name use count (%hu) exceeded",
1540 		    *name_count);
1541 		return -1;
1542 	}
1543 
1544 
1545 
1546 	if (mcopy(ms, p, m->type, m->flag & INDIR, s,
1547 	    CAST(uint32_t, offset + o), CAST(uint32_t, nbytes), m) == -1)
1548 		return -1;
1549 
1550 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1551 		fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1552 		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1553 		    "u, il=%hu, nc=%hu)\n",
1554 		    m->type, m->flag, offset, o, nbytes,
1555 		    *indir_count, *name_count);
1556 		mdebug(offset, RCAST(char *, RCAST(void *, p)),
1557 		    sizeof(union VALUETYPE));
1558 #ifndef COMPILE_ONLY
1559 		file_mdump(m);
1560 #endif
1561 	}
1562 
1563 	if (m->flag & INDIR) {
1564 		intmax_t off = m->in_offset;
1565 		const int sgn = m->in_op & FILE_OPSIGNED;
1566 		if (m->in_op & FILE_OPINDIRECT) {
1567 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1568 			    RCAST(const void *, s + offset + off));
1569 			switch (cvt_flip(m->in_type, flip)) {
1570 			case FILE_BYTE:
1571 				if (OFFSET_OOB(nbytes, offset + off, 1))
1572 					return 0;
1573 				off = SEXT(sgn,8,q->b);
1574 				break;
1575 			case FILE_SHORT:
1576 				if (OFFSET_OOB(nbytes, offset + off, 2))
1577 					return 0;
1578 				off = SEXT(sgn,16,q->h);
1579 				break;
1580 			case FILE_BESHORT:
1581 				if (OFFSET_OOB(nbytes, offset + off, 2))
1582 					return 0;
1583 				off = SEXT(sgn,16,BE16(q));
1584 				break;
1585 			case FILE_LESHORT:
1586 				if (OFFSET_OOB(nbytes, offset + off, 2))
1587 					return 0;
1588 				off = SEXT(sgn,16,LE16(q));
1589 				break;
1590 			case FILE_LONG:
1591 				if (OFFSET_OOB(nbytes, offset + off, 4))
1592 					return 0;
1593 				off = SEXT(sgn,32,q->l);
1594 				break;
1595 			case FILE_BELONG:
1596 			case FILE_BEID3:
1597 				if (OFFSET_OOB(nbytes, offset + off, 4))
1598 					return 0;
1599 				off = SEXT(sgn,32,BE32(q));
1600 				break;
1601 			case FILE_LEID3:
1602 			case FILE_LELONG:
1603 				if (OFFSET_OOB(nbytes, offset + off, 4))
1604 					return 0;
1605 				off = SEXT(sgn,32,LE32(q));
1606 				break;
1607 			case FILE_MELONG:
1608 				if (OFFSET_OOB(nbytes, offset + off, 4))
1609 					return 0;
1610 				off = SEXT(sgn,32,ME32(q));
1611 				break;
1612 			case FILE_BEQUAD:
1613 				if (OFFSET_OOB(nbytes, offset + off, 8))
1614 					return 0;
1615 				off = SEXT(sgn,64,BE64(q));
1616 				break;
1617 			case FILE_LEQUAD:
1618 				if (OFFSET_OOB(nbytes, offset + off, 8))
1619 					return 0;
1620 				off = SEXT(sgn,64,LE64(q));
1621 				break;
1622 			default:
1623 				abort();
1624 			}
1625 			if ((ms->flags & MAGIC_DEBUG) != 0)
1626 				fprintf(stderr, "indirect offs=%jd\n", off);
1627 		}
1628 		switch (in_type = cvt_flip(m->in_type, flip)) {
1629 		case FILE_BYTE:
1630 			if (OFFSET_OOB(nbytes, offset, 1))
1631 				return 0;
1632 			offset = do_ops(m, SEXT(sgn,8,p->b), off);
1633 			break;
1634 		case FILE_BESHORT:
1635 			if (OFFSET_OOB(nbytes, offset, 2))
1636 				return 0;
1637 			offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1638 			break;
1639 		case FILE_LESHORT:
1640 			if (OFFSET_OOB(nbytes, offset, 2))
1641 				return 0;
1642 			offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1643 			break;
1644 		case FILE_SHORT:
1645 			if (OFFSET_OOB(nbytes, offset, 2))
1646 				return 0;
1647 			offset = do_ops(m, SEXT(sgn,16,p->h), off);
1648 			break;
1649 		case FILE_BELONG:
1650 		case FILE_BEID3:
1651 			if (OFFSET_OOB(nbytes, offset, 4))
1652 				return 0;
1653 			lhs = BE32(p);
1654 			if (in_type == FILE_BEID3)
1655 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1656 			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1657 			break;
1658 		case FILE_LELONG:
1659 		case FILE_LEID3:
1660 			if (OFFSET_OOB(nbytes, offset, 4))
1661 				return 0;
1662 			lhs = LE32(p);
1663 			if (in_type == FILE_LEID3)
1664 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1665 			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1666 			break;
1667 		case FILE_MELONG:
1668 			if (OFFSET_OOB(nbytes, offset, 4))
1669 				return 0;
1670 			offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1671 			break;
1672 		case FILE_LONG:
1673 			if (OFFSET_OOB(nbytes, offset, 4))
1674 				return 0;
1675 			offset = do_ops(m, SEXT(sgn,32,p->l), off);
1676 			break;
1677 		case FILE_LEQUAD:
1678 			if (OFFSET_OOB(nbytes, offset, 8))
1679 				return 0;
1680 			offset = do_ops(m, SEXT(sgn,64,LE64(p)), off);
1681 			break;
1682 		case FILE_BEQUAD:
1683 			if (OFFSET_OOB(nbytes, offset, 8))
1684 				return 0;
1685 			offset = do_ops(m, SEXT(sgn,64,BE64(p)), off);
1686 			break;
1687 		default:
1688 			abort();
1689 		}
1690 
1691 		if (m->flag & INDIROFFADD) {
1692 			offset += ms->c.li[cont_level-1].off;
1693 			if (offset == 0) {
1694 				if ((ms->flags & MAGIC_DEBUG) != 0)
1695 					fprintf(stderr,
1696 					    "indirect *zero* offset\n");
1697 				return 0;
1698 			}
1699 			if ((ms->flags & MAGIC_DEBUG) != 0)
1700 				fprintf(stderr, "indirect +offs=%u\n", offset);
1701 		}
1702 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1703 			return -1;
1704 		ms->offset = offset;
1705 
1706 		if ((ms->flags & MAGIC_DEBUG) != 0) {
1707 			mdebug(offset, RCAST(char *, RCAST(void *, p)),
1708 			    sizeof(union VALUETYPE));
1709 #ifndef COMPILE_ONLY
1710 			file_mdump(m);
1711 #endif
1712 		}
1713 	}
1714 
1715 	/* Verify we have enough data to match magic type */
1716 	switch (m->type) {
1717 	case FILE_BYTE:
1718 		if (OFFSET_OOB(nbytes, offset, 1))
1719 			return 0;
1720 		break;
1721 
1722 	case FILE_SHORT:
1723 	case FILE_BESHORT:
1724 	case FILE_LESHORT:
1725 		if (OFFSET_OOB(nbytes, offset, 2))
1726 			return 0;
1727 		break;
1728 
1729 	case FILE_LONG:
1730 	case FILE_BELONG:
1731 	case FILE_LELONG:
1732 	case FILE_MELONG:
1733 	case FILE_DATE:
1734 	case FILE_BEDATE:
1735 	case FILE_LEDATE:
1736 	case FILE_MEDATE:
1737 	case FILE_LDATE:
1738 	case FILE_BELDATE:
1739 	case FILE_LELDATE:
1740 	case FILE_MELDATE:
1741 	case FILE_FLOAT:
1742 	case FILE_BEFLOAT:
1743 	case FILE_LEFLOAT:
1744 		if (OFFSET_OOB(nbytes, offset, 4))
1745 			return 0;
1746 		break;
1747 
1748 	case FILE_DOUBLE:
1749 	case FILE_BEDOUBLE:
1750 	case FILE_LEDOUBLE:
1751 		if (OFFSET_OOB(nbytes, offset, 8))
1752 			return 0;
1753 		break;
1754 
1755 	case FILE_STRING:
1756 	case FILE_PSTRING:
1757 	case FILE_SEARCH:
1758 		if (OFFSET_OOB(nbytes, offset, m->vallen))
1759 			return 0;
1760 		break;
1761 
1762 	case FILE_REGEX:
1763 		if (nbytes < offset)
1764 			return 0;
1765 		break;
1766 
1767 	case FILE_INDIRECT:
1768 		if (m->str_flags & INDIRECT_RELATIVE)
1769 			offset += CAST(uint32_t, o);
1770 		if (offset == 0)
1771 			return 0;
1772 
1773 		if (nbytes < offset)
1774 			return 0;
1775 
1776 		if ((pb = file_push_buffer(ms)) == NULL)
1777 			return -1;
1778 
1779 		(*indir_count)++;
1780 		bb = *b;
1781 		bb.fbuf = s + offset;
1782 		bb.flen = nbytes - offset;
1783 		rv = file_softmagic(ms, &bb,
1784 		    indir_count, name_count, BINTEST, text);
1785 
1786 		if ((ms->flags & MAGIC_DEBUG) != 0)
1787 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1788 
1789 		rbuf = file_pop_buffer(ms, pb);
1790 		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1791 			return -1;
1792 
1793 		if (rv == 1) {
1794 			if ((ms->flags & MAGIC_NODESC) == 0 &&
1795 			    file_printf(ms, F(ms, m->desc, "%u"), offset) == -1)
1796 			{
1797 				free(rbuf);
1798 				return -1;
1799 			}
1800 			if (file_printf(ms, "%s", rbuf) == -1) {
1801 				free(rbuf);
1802 				return -1;
1803 			}
1804 		}
1805 		free(rbuf);
1806 		return rv;
1807 
1808 	case FILE_USE:
1809 		if (nbytes < offset)
1810 			return 0;
1811 		rbuf = m->value.s;
1812 		if (*rbuf == '^') {
1813 			rbuf++;
1814 			flip = !flip;
1815 		}
1816 		if (file_magicfind(ms, rbuf, &ml) == -1) {
1817 			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1818 			return -1;
1819 		}
1820 		(*name_count)++;
1821 		oneed_separator = *need_separator;
1822 		if (m->flag & NOSPACE)
1823 			*need_separator = 0;
1824 		rv = match(ms, ml.magic, ml.nmagic, b, offset + o,
1825 		    mode, text, flip, indir_count, name_count,
1826 		    printed_something, need_separator, returnval, found_match);
1827 		(*name_count)--;
1828 		if (rv != 1)
1829 		    *need_separator = oneed_separator;
1830 		return rv;
1831 
1832 	case FILE_NAME:
1833 		if (ms->flags & MAGIC_NODESC)
1834 			return 1;
1835 		if (file_printf(ms, "%s", m->desc) == -1)
1836 			return -1;
1837 		return 1;
1838 	case FILE_DER:
1839 	case FILE_DEFAULT:	/* nothing to check */
1840 	case FILE_CLEAR:
1841 	default:
1842 		break;
1843 	}
1844 	if (!mconvert(ms, m, flip))
1845 		return 0;
1846 	return 1;
1847 }
1848 
1849 private uint64_t
1850 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1851 {
1852 	/*
1853 	 * Convert the source args to unsigned here so that (1) the
1854 	 * compare will be unsigned as it is in strncmp() and (2) so
1855 	 * the ctype functions will work correctly without extra
1856 	 * casting.
1857 	 */
1858 	const unsigned char *a = RCAST(const unsigned char *, s1);
1859 	const unsigned char *b = RCAST(const unsigned char *, s2);
1860 	const unsigned char *eb = b + len;
1861 	uint64_t v;
1862 
1863 	/*
1864 	 * What we want here is v = strncmp(s1, s2, len),
1865 	 * but ignoring any nulls.
1866 	 */
1867 	v = 0;
1868 	if (0L == flags) { /* normal string: do it fast */
1869 		while (len-- > 0)
1870 			if ((v = *b++ - *a++) != '\0')
1871 				break;
1872 	}
1873 	else { /* combine the others */
1874 		while (len-- > 0) {
1875 			if (b >= eb) {
1876 				v = 1;
1877 				break;
1878 			}
1879 			if ((flags & STRING_IGNORE_LOWERCASE) &&
1880 			    islower(*a)) {
1881 				if ((v = tolower(*b++) - *a++) != '\0')
1882 					break;
1883 			}
1884 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1885 			    isupper(*a)) {
1886 				if ((v = toupper(*b++) - *a++) != '\0')
1887 					break;
1888 			}
1889 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1890 			    isspace(*a)) {
1891 				a++;
1892 				if (isspace(*b++)) {
1893 					if (!isspace(*a))
1894 						while (b < eb && isspace(*b))
1895 							b++;
1896 				}
1897 				else {
1898 					v = 1;
1899 					break;
1900 				}
1901 			}
1902 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1903 			    isspace(*a)) {
1904 				a++;
1905 				while (b < eb && isspace(*b))
1906 					b++;
1907 			}
1908 			else {
1909 				if ((v = *b++ - *a++) != '\0')
1910 					break;
1911 			}
1912 		}
1913 	}
1914 	return v;
1915 }
1916 
1917 private uint64_t
1918 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1919 {
1920 	/*
1921 	 * XXX - The 16-bit string compare probably needs to be done
1922 	 * differently, especially if the flags are to be supported.
1923 	 * At the moment, I am unsure.
1924 	 */
1925 	flags = 0;
1926 	return file_strncmp(a, b, len, flags);
1927 }
1928 
1929 private int
1930 magiccheck(struct magic_set *ms, struct magic *m)
1931 {
1932 	uint64_t l = m->value.q;
1933 	uint64_t v;
1934 	float fl, fv;
1935 	double dl, dv;
1936 	int matched;
1937 	union VALUETYPE *p = &ms->ms_value;
1938 
1939 	switch (m->type) {
1940 	case FILE_BYTE:
1941 		v = p->b;
1942 		break;
1943 
1944 	case FILE_SHORT:
1945 	case FILE_BESHORT:
1946 	case FILE_LESHORT:
1947 		v = p->h;
1948 		break;
1949 
1950 	case FILE_LONG:
1951 	case FILE_BELONG:
1952 	case FILE_LELONG:
1953 	case FILE_MELONG:
1954 	case FILE_DATE:
1955 	case FILE_BEDATE:
1956 	case FILE_LEDATE:
1957 	case FILE_MEDATE:
1958 	case FILE_LDATE:
1959 	case FILE_BELDATE:
1960 	case FILE_LELDATE:
1961 	case FILE_MELDATE:
1962 		v = p->l;
1963 		break;
1964 
1965 	case FILE_QUAD:
1966 	case FILE_LEQUAD:
1967 	case FILE_BEQUAD:
1968 	case FILE_QDATE:
1969 	case FILE_BEQDATE:
1970 	case FILE_LEQDATE:
1971 	case FILE_QLDATE:
1972 	case FILE_BEQLDATE:
1973 	case FILE_LEQLDATE:
1974 	case FILE_QWDATE:
1975 	case FILE_BEQWDATE:
1976 	case FILE_LEQWDATE:
1977 		v = p->q;
1978 		break;
1979 
1980 	case FILE_FLOAT:
1981 	case FILE_BEFLOAT:
1982 	case FILE_LEFLOAT:
1983 		fl = m->value.f;
1984 		fv = p->f;
1985 		switch (m->reln) {
1986 		case 'x':
1987 			matched = 1;
1988 			break;
1989 
1990 		case '!':
1991 			matched = fv != fl;
1992 			break;
1993 
1994 		case '=':
1995 			matched = fv == fl;
1996 			break;
1997 
1998 		case '>':
1999 			matched = fv > fl;
2000 			break;
2001 
2002 		case '<':
2003 			matched = fv < fl;
2004 			break;
2005 
2006 		default:
2007 			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
2008 			    m->reln);
2009 			return -1;
2010 		}
2011 		return matched;
2012 
2013 	case FILE_DOUBLE:
2014 	case FILE_BEDOUBLE:
2015 	case FILE_LEDOUBLE:
2016 		dl = m->value.d;
2017 		dv = p->d;
2018 		switch (m->reln) {
2019 		case 'x':
2020 			matched = 1;
2021 			break;
2022 
2023 		case '!':
2024 			matched = dv != dl;
2025 			break;
2026 
2027 		case '=':
2028 			matched = dv == dl;
2029 			break;
2030 
2031 		case '>':
2032 			matched = dv > dl;
2033 			break;
2034 
2035 		case '<':
2036 			matched = dv < dl;
2037 			break;
2038 
2039 		default:
2040 			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
2041 			return -1;
2042 		}
2043 		return matched;
2044 
2045 	case FILE_DEFAULT:
2046 	case FILE_CLEAR:
2047 		l = 0;
2048 		v = 0;
2049 		break;
2050 
2051 	case FILE_STRING:
2052 	case FILE_PSTRING:
2053 		l = 0;
2054 		v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
2055 		    m->str_flags);
2056 		break;
2057 
2058 	case FILE_BESTRING16:
2059 	case FILE_LESTRING16:
2060 		l = 0;
2061 		v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen),
2062 		    m->str_flags);
2063 		break;
2064 
2065 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2066 		size_t slen;
2067 		size_t idx;
2068 
2069 		if (ms->search.s == NULL)
2070 			return 0;
2071 
2072 		slen = MIN(m->vallen, sizeof(m->value.s));
2073 		l = 0;
2074 		v = 0;
2075 #ifdef HAVE_MEMMEM
2076 		if (slen > 0 && m->str_flags == 0) {
2077 			const char *found;
2078 			idx = m->str_range + slen;
2079 			if (m->str_range == 0 || ms->search.s_len < idx)
2080 				idx = ms->search.s_len;
2081 			found = CAST(const char *, memmem(ms->search.s, idx,
2082 			    m->value.s, slen));
2083 			if (!found)
2084 				return 0;
2085 			idx = found - ms->search.s;
2086 			ms->search.offset += idx;
2087 			ms->search.rm_len = ms->search.s_len - idx;
2088 			break;
2089 		}
2090 #endif
2091 
2092 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
2093 			if (slen + idx > ms->search.s_len)
2094 				return 0;
2095 
2096 			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2097 			    m->str_flags);
2098 			if (v == 0) {	/* found match */
2099 				ms->search.offset += idx;
2100 				ms->search.rm_len = ms->search.s_len - idx;
2101 				break;
2102 			}
2103 		}
2104 		break;
2105 	}
2106 	case FILE_REGEX: {
2107 		int rc;
2108 		file_regex_t rx;
2109 		const char *search;
2110 
2111 		if (ms->search.s == NULL)
2112 			return 0;
2113 
2114 		l = 0;
2115 		rc = file_regcomp(&rx, m->value.s,
2116 		    REG_EXTENDED|REG_NEWLINE|
2117 		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2118 		if (rc) {
2119 			file_regerror(&rx, rc, ms);
2120 			v = CAST(uint64_t, -1);
2121 		} else {
2122 			regmatch_t pmatch;
2123 			size_t slen = ms->search.s_len;
2124 			char *copy;
2125 			if (slen != 0) {
2126 			    copy = CAST(char *, malloc(slen));
2127 			    if (copy == NULL)  {
2128 				file_regfree(&rx);
2129 				file_error(ms, errno,
2130 				    "can't allocate %" SIZE_T_FORMAT "u bytes",
2131 				    slen);
2132 				return -1;
2133 			    }
2134 			    memcpy(copy, ms->search.s, slen);
2135 			    copy[--slen] = '\0';
2136 			    search = copy;
2137 			} else {
2138 			    search = CCAST(char *, "");
2139 			    copy = NULL;
2140 			}
2141 			rc = file_regexec(&rx, RCAST(const char *, search),
2142 			    1, &pmatch, 0);
2143 			free(copy);
2144 			switch (rc) {
2145 			case 0:
2146 				ms->search.s += CAST(int, pmatch.rm_so);
2147 				ms->search.offset += CAST(size_t, pmatch.rm_so);
2148 				ms->search.rm_len = CAST(size_t,
2149 				    pmatch.rm_eo - pmatch.rm_so);
2150 				v = 0;
2151 				break;
2152 
2153 			case REG_NOMATCH:
2154 				v = 1;
2155 				break;
2156 
2157 			default:
2158 				file_regerror(&rx, rc, ms);
2159 				v = CAST(uint64_t, -1);
2160 				break;
2161 			}
2162 		}
2163 		file_regfree(&rx);
2164 		if (v == CAST(uint64_t, -1))
2165 			return -1;
2166 		break;
2167 	}
2168 	case FILE_INDIRECT:
2169 	case FILE_USE:
2170 	case FILE_NAME:
2171 		return 1;
2172 	case FILE_DER:
2173 		matched = der_cmp(ms, m);
2174 		if (matched == -1) {
2175 			if ((ms->flags & MAGIC_DEBUG) != 0) {
2176 				(void) fprintf(stderr,
2177 				    "EOF comparing DER entries");
2178 			}
2179 			return 0;
2180 		}
2181 		return matched;
2182 	default:
2183 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2184 		return -1;
2185 	}
2186 
2187 	v = file_signextend(ms, m, v);
2188 
2189 	switch (m->reln) {
2190 	case 'x':
2191 		if ((ms->flags & MAGIC_DEBUG) != 0)
2192 			(void) fprintf(stderr, "%" INT64_T_FORMAT
2193 			    "u == *any* = 1\n", CAST(unsigned long long, v));
2194 		matched = 1;
2195 		break;
2196 
2197 	case '!':
2198 		matched = v != l;
2199 		if ((ms->flags & MAGIC_DEBUG) != 0)
2200 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2201 			    INT64_T_FORMAT "u = %d\n",
2202 			    CAST(unsigned long long, v),
2203 			    CAST(unsigned long long, l), matched);
2204 		break;
2205 
2206 	case '=':
2207 		matched = v == l;
2208 		if ((ms->flags & MAGIC_DEBUG) != 0)
2209 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2210 			    INT64_T_FORMAT "u = %d\n",
2211 			    CAST(unsigned long long, v),
2212 			    CAST(unsigned long long, l), matched);
2213 		break;
2214 
2215 	case '>':
2216 		if (m->flag & UNSIGNED) {
2217 			matched = v > l;
2218 			if ((ms->flags & MAGIC_DEBUG) != 0)
2219 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2220 				    "u > %" INT64_T_FORMAT "u = %d\n",
2221 				    CAST(unsigned long long, v),
2222 				    CAST(unsigned long long, l), matched);
2223 		}
2224 		else {
2225 			matched = CAST(int64_t, v) > CAST(int64_t, l);
2226 			if ((ms->flags & MAGIC_DEBUG) != 0)
2227 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2228 				    "d > %" INT64_T_FORMAT "d = %d\n",
2229 				    CAST(long long, v),
2230 				    CAST(long long, l), matched);
2231 		}
2232 		break;
2233 
2234 	case '<':
2235 		if (m->flag & UNSIGNED) {
2236 			matched = v < l;
2237 			if ((ms->flags & MAGIC_DEBUG) != 0)
2238 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2239 				    "u < %" INT64_T_FORMAT "u = %d\n",
2240 				    CAST(unsigned long long, v),
2241 				    CAST(unsigned long long, l), matched);
2242 		}
2243 		else {
2244 			matched = CAST(int64_t, v) < CAST(int64_t, l);
2245 			if ((ms->flags & MAGIC_DEBUG) != 0)
2246 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2247 				    "d < %" INT64_T_FORMAT "d = %d\n",
2248 				     CAST(long long, v),
2249 				     CAST(long long, l), matched);
2250 		}
2251 		break;
2252 
2253 	case '&':
2254 		matched = (v & l) == l;
2255 		if ((ms->flags & MAGIC_DEBUG) != 0)
2256 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2257 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2258 			    "x) = %d\n", CAST(unsigned long long, v),
2259 			    CAST(unsigned long long, l),
2260 			    CAST(unsigned long long, l),
2261 			    matched);
2262 		break;
2263 
2264 	case '^':
2265 		matched = (v & l) != l;
2266 		if ((ms->flags & MAGIC_DEBUG) != 0)
2267 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2268 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2269 			    "x) = %d\n", CAST(unsigned long long, v),
2270 			    CAST(unsigned long long, l),
2271 			    CAST(unsigned long long, l), matched);
2272 		break;
2273 
2274 	default:
2275 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2276 		    m->reln);
2277 		return -1;
2278 	}
2279 
2280 	return matched;
2281 }
2282 
2283 private int
2284 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2285 {
2286 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2287 		if (print_sep(ms, firstline) == -1)
2288 			return -1;
2289 		if (file_printf(ms, "%.8s", m->apple) == -1)
2290 			return -1;
2291 		return 1;
2292 	}
2293 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2294 		if (print_sep(ms, firstline) == -1)
2295 			return -1;
2296 		if (file_printf(ms, "%s", m->ext) == -1)
2297 			return -1;
2298 		return 1;
2299 	}
2300 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2301 		char buf[1024];
2302 		const char *p;
2303 		if (print_sep(ms, firstline) == -1)
2304 			return -1;
2305 		if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
2306 			p = m->mimetype;
2307 		else
2308 			p = buf;
2309 		if (file_printf(ms, "%s", p) == -1)
2310 			return -1;
2311 		return 1;
2312 	}
2313 	return 0;
2314 }
2315 
2316 private int
2317 print_sep(struct magic_set *ms, int firstline)
2318 {
2319 	if (firstline)
2320 		return 0;
2321 	/*
2322 	 * we found another match
2323 	 * put a newline and '-' to do some simple formatting
2324 	 */
2325 	return file_separator(ms);
2326 }
2327