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