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