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